#include "dokerwindow.h"
#include "dokereditor.h"
#include "../doker.h"
#include "../dokermodel.h"
#include "../dokerversion.h"
#include "../objects/pageobject.h"
#include "../objects/textobject.h"

#include <QtCore/qdebug.h>
#include <QtCore/qfileinfo.h>
#include <QtGui/qgraphicsitem.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qmessagebox.h>
#include <QtGui/qprinter.h>
#include <QtGui/qscrollbar.h>

DokerWindow::DokerWindow(DokerModel *model, QWidget *parent) :
    QSplitter(parent)
{
    m_model = model;
    m_editor = new DokerTabEditor(this);
    addWidget(m_editor);
    m_scene = new QGraphicsScene(this);
    m_viewer = new QGraphicsView(m_scene);
    m_viewer->setBackgroundBrush(QBrush(Qt::lightGray));
    m_viewer->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    addWidget(m_viewer);
    m_editor->setTabsClosable(true);
    connect(m_editor, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
    connect(m_model, SIGNAL(textEditRequested(QString)), this, SLOT(openEditor(QString)));
    connect(m_model, SIGNAL(modified(QString,bool)), this, SLOT(update(QString,bool)));
    editorSetVisible(false);
    setSizes(QList<int>() << 50 << 50);
    clearViewer();
}

DokerEditor *DokerWindow::addEditorItem(const QString &fileName, const QString &content)
{
    DokerEditor *editorItem = new DokerEditor(fileName, content, this);
    m_editor->addTab(editorItem, QIcon(":/images/script.png"), QFileInfo(fileName).fileName());
    connect(editorItem, SIGNAL(modified(bool)), this, SLOT(update(bool)));
    return editorItem;
}

void DokerWindow::addPage(PageObject *page)
{
    m_originY = page->pixelOriginY();
    m_pageItem = m_scene->addRect(page->pixelFrameRect(), Qt::NoPen, Qt::NoBrush);
    m_pageItem->setPen(Qt::NoPen);
    m_pageItem->setBrush(Qt::NoBrush);

    //m_scene->addItem(m_pageItem);

    QGraphicsRectItem *paperItem = new QGraphicsRectItem(page->pixelPageRect(), m_pageItem);
    paperItem->setPen(Qt::NoPen);
    paperItem->setBrush(Qt::white);
    m_pages.append(paperItem);

    for (int i = 0; i < page->areaCount(); ++i)
    {
        QGraphicsRectItem *areaItem = new QGraphicsRectItem(page->pixelAreaRect(i), m_pageItem);
        areaItem->setPen(QPen(Qt::lightGray, 0, Qt::DashLine));
        areaItem->setBrush(Qt::NoBrush);
        m_unprinted.append(areaItem);
    }

    for (int i = 0; i < page->textCount(); ++i)
    {
        //TextObject *t = page->text(i);
        addText(page->text(i));
/*
        QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(t->content(), m_pageItem);
        textItem->setFont(t->font());
        textItem->moveBy(t->pixelX(), t->pixelY() + m_originY);
        QFontMetrics fm(t->font());
        QRect r(t->pixelX(), t->pixelY(), fm.width(t->content()), fm.height());
        QGraphicsRectItem *textRectItem = new QGraphicsRectItem(r, m_pageItem);*/
    }

    //m_pageItem->moveBy(0, m_pageOffset);
    //m_pageOffset += page->height() + Doker::space;
    const int w = page->pixelFrameRect().width();//page->pixelWidth() + toPixels(2*Doker::space);
    if (m_maxPageWidth < w)
        m_maxPageWidth = w;
    m_scene->setSceneRect(m_scene->itemsBoundingRect());
    fitWidth();

    qDebug() << "DokerWindow::addPage";
}

void DokerWindow::addText(TextObject *text)
{
    if (text->pixelX() >= 0 && text->pixelY() >= 0)
    {
        QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(text->content(), m_pageItem);
        textItem->setFont(text->font());
        textItem->setPen(Qt::NoPen);//QPen(text->color()));
        textItem->setBrush(QBrush(text->color()));
        textItem->moveBy(text->pixelX(), text->pixelY() + m_originY);
        QFontMetrics fm(text->font());
        QRect r(text->pixelX(), text->pixelY() + m_originY, fm.width(text->content()), fm.height());
        QGraphicsRectItem *ri = new QGraphicsRectItem(r, m_pageItem);
        ri->setPen(QPen(text->color(), 0, Qt::DotLine));
        m_unprinted.append(ri);
    }
    qDebug() << "DokerWindow::addText" << text->content();
}

void DokerWindow::apply()
{
    for (int i = 0; i < m_editor->count(); ++i)
    {
        DokerEditor *editorItem = qobject_cast<DokerEditor*>(m_editor->widget(i));
        editorItem->apply();
    }
}

void DokerWindow::clearViewer()
{
    m_pageItem = 0;
    m_scene->clear(); // TODO: Replace by ping-pong drawing technology

    m_maxPageWidth = 0.0;
    m_originY = 0;
    m_pages.clear();
    m_unprinted.clear();
}

void DokerWindow::closeTab(int index)
{
    DokerEditor *editorItem = qobject_cast<DokerEditor*>(m_editor->widget(index));
    if (editorItem)
    {
        if (editorItem->isModified())
        {
            int res = QMessageBox::question(this, tr("Unapplied Changes"),
                                            QString(tr("There are unapplied changes in editor window."))
                                            + "<br><br>" + tr("Would you apply it now?"),
                                            QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
                                            QMessageBox::Cancel);
            if (res == QMessageBox::Cancel)
                return;
            else
            {
                if (res == QMessageBox::Yes)
                    editorItem->apply();
            }
        }
        m_editor->removeTab(index);
        if (!m_editor->count())
            editorSetVisible(false);
    }
}

void DokerWindow::closeTabs()
{
    m_editor->clear();
    editorSetVisible(false);
}

DokerTabEditor *DokerWindow::editor()
{
    return m_editor;
}

void DokerWindow::editorSetVisible(bool visible)
{
    m_editor->setVisible(visible);
    emit editorVisibilityChanged(visible);
}

void DokerWindow::exportToPdf(const QString &fullPdfName)
{
    if (m_pages.isEmpty())
        return;
    QPrinter printer(QPrinter::HighResolution);
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName(fullPdfName);
    printer.setPageMargins(0, 0, 0, 0, QPrinter::Millimeter);
    printer.setCreator(QString("Doker %1 (http://doker.org)").arg(DOKER_VER_STR3));
    printer.setPaperSize(m_pages.first()->rect().size(), QPrinter::Millimeter);
    QPainter painter;
    painter.begin(&printer);
    for (int i = 0; i < m_pages.count(); ++i)
    {
        QRectF srcRect = m_pages.at(i)->rect();
        if (i)
        {
            printer.setPaperSize(srcRect.size(), QPrinter::Millimeter);
            printer.newPage();
        }
        m_scene->render(&painter, printer.paperRect(), srcRect, Qt::IgnoreAspectRatio);
    }
    painter.end();

}

DokerEditor *DokerWindow::findEditorItem(const QString &fileName)
{
    DokerEditor *editorItem = 0;
    for (int i = 0; (i < m_editor->count()) && !editorItem; ++i)
    {
        DokerEditor *item = qobject_cast<DokerEditor*>(m_editor->widget(i));
        if (item->fileName() == fileName)
            editorItem = item;
    }
    return editorItem;
}

void DokerWindow::fitWidth()
{
    qreal newScale = (qreal)m_viewer->viewport()->width() / m_maxPageWidth;
    QMatrix oldMatrix = m_viewer->matrix();
    m_viewer->resetMatrix();
    m_viewer->translate(oldMatrix.dx(), oldMatrix.dy());
    m_viewer->scale(newScale, newScale);
}

void DokerWindow::update(bool modified)
{
    DokerEditor *editorItem = qobject_cast<DokerEditor*>(sender());
    const int index = m_editor->indexOf(editorItem);
    if (index >= 0)
        m_editor->highlightTab(index, modified);
    if (!modified) // Changes applied
    {
        QByteArray fileData;
        fileData.append(editorItem->toPlainText());
        m_model->setFileData(editorItem->fileName(), fileData);
    }
}

void DokerWindow::update(const QString &fileName, bool modified)
{
    for (int i = 0; i < m_editor->count(); ++i)
    {
        DokerEditor *editorItem = qobject_cast<DokerEditor*>(m_editor->widget(i));
        if (editorItem->fileName() == fileName)
            m_editor->setTabText(i, fileName + (modified ? "*" : ""));
    }
}

void DokerWindow::openEditor(const QString &fileName)
{
    if (m_editor->isHidden())
        editorSetVisible(true);
    DokerEditor *editorItem = findEditorItem(fileName);
    if (!editorItem)
        editorItem = addEditorItem(fileName, m_model->fileData(fileName));
    m_editor->setCurrentWidget(editorItem);
}

QGraphicsScene *DokerWindow::scene()
{
    return m_scene;
}

QGraphicsView *DokerWindow::viewer()
{
    return m_viewer;
}

void DokerWindow::viewerSetVisible(bool visible)
{
    m_viewer->setVisible(visible);
    emit viewerVisibilityChanged(visible);
}

void DokerWindow::viewUnprinted(bool visible)
{
    for (int i = 0; i < m_unprinted.count(); ++i)
        m_unprinted.at(i)->setVisible(visible);
}
